package cn.liutao.auth.service;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.liutao.auth.entity.param.LoginParam;
import cn.liutao.auth.entity.param.RegisterParam;
import cn.liutao.auth.entity.po.User;
import cn.liutao.auth.mapper.UserMapper;
import cn.liutao.common.entity.LoginUser;
import cn.liutao.common.enums.CommonEnum;
import cn.liutao.common.exception.BadRequestException;
import cn.liutao.common.exception.CaptchaException;
import cn.liutao.common.exception.ForbiddenException;
import cn.liutao.common.utils.RedisUtils;
import cn.liutao.common.utils.ServletUtils;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;

import java.awt.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;


/**
 * @author liutao
 * @Description 登录、注册、验证码业务层代码
 * @date 2023/10/30 19:43
 * @Version 1.0
 */
@Slf4j
public class AuthService {

    private static volatile AuthService instance;
    private UserMapper userMapper;
    //私有构造方法
    private AuthService(){
        userMapper = ServletUtils.getMapper(UserMapper.class);
    }


    /**
     * 双重检查锁实现单例
     * @return
     */
    public static AuthService getInstance(){
        if (instance==null){
            synchronized (AuthService.class){
                if (instance==null){
                    instance = new AuthService();
                }
            }
        }
        return instance;
    }

    /**
     * 生成验证码
     * @param type
     * @param width
     * @param height
     * @param codeCount
     * @param typeCount
     * @return
     */
    public Map genCaptcha(Integer type, int width, int height, int codeCount, int typeCount){
        Map map = new LinkedHashMap();
        AbstractCaptcha captcha = null;
        switch (type){
            case 1:
                captcha = CaptchaUtil.createLineCaptcha(width,height,codeCount,typeCount);
                break;
            case 2:
                captcha = CaptchaUtil.createCircleCaptcha(width, height,codeCount,typeCount);
                break;
            case 3:
                captcha = CaptchaUtil.createShearCaptcha(width,height,codeCount,typeCount);
        }
        captcha.setTextAlpha(0.3f);
        captcha.setBackground(Color.WHITE);
        String code = captcha.getCode();
        String str = "data:image/jpeg;base64,";
        String imageBase64 = str + captcha.getImageBase64();
        map.put("captchaImg",imageBase64);
        map.put("key",code);
        return map;
    }

    /**
     * 登录逻辑
     *
     * @param loginParam
     * @return
     */
    public User login(LoginParam loginParam) {

        User user = userMapper.selectOneByQuery(QueryWrapper.create()
                .where(User::getUsername).eq(loginParam.getUsername())
                .and(User::getPassword).eq(SecureUtil.md5(loginParam.getPassword()))
        );
        if (ObjectUtil.isNull(user)){
            throw new BadRequestException("用户名或者密码错误");
        }
        //管理员登录
        if (loginParam.getIsAdmin().compareTo(CommonEnum.SYS_IS_ADMIN.getIntValue())==0){
            //判断是否具有管理员权限
            if (user.getIsAdmin().compareTo(CommonEnum.SYS_IS_ADMIN.getIntValue())!=0){
                throw new ForbiddenException("没有登录权限,请联系管理员");
            }
        }
        return user;
    }

    /**
     * 校验验证码
     *
     * @param loginParam
     * @return
     */
    public void verify(LoginParam loginParam){
        String code = loginParam.getCode();
        if (StrUtil.isEmpty(code)){
            throw new CaptchaException("验证码不能为空");
        }
        String verify = RedisUtils.get(CommonEnum.CAPTCHA_KEY.getValue() + loginParam.getKey());
        log.info("当前存储的验证码：{}用户上传的验证码：{}",verify,code);
        if (ObjectUtil.isNull(verify)){
            throw new CaptchaException("验证码已过期");
        }
        if (!code.equals(verify)){
            throw new CaptchaException("验证码不正确");
        }
        //清除验证码 缓存
        RedisUtils.remove(CommonEnum.CAPTCHA_KEY.getValue() + loginParam.getKey());
    }

    /**
     * 实现注册功能
     *
     * @param registerParam
     * @return
     */
    public Boolean register(RegisterParam registerParam){
        User user = userMapper.selectOneByQuery(QueryWrapper.create().where(User::getUsername).eq(registerParam.getUsername()));
        if (ObjectUtil.isNotNull(user)){
            throw new BadRequestException("该用户名已被注册");
        }
        if (!registerParam.getPassword().equals(registerParam.getPasswordAgain())){
            throw new BadRequestException("两次输入的密码不一致");
        }
        User userDB = new User();
        userDB.setUsername(registerParam.getUsername());
        userDB.setNickName("新用户"+ StrUtil.replace(UUID.randomUUID().toString(),"-","").substring(0,5));
        userDB.setIsAdmin(0);
        userDB.setPassword(SecureUtil.md5(registerParam.getPassword()));
        userMapper.insert(userDB);
        return true;
    }

    /**
     * 校验密码
     * @param userId
     * @param password
     * @return
     */
    public boolean verifyPassword(Integer userId, String password) {
        User user = userMapper.selectOneById(userId);
        if (user!=null &&user.getPassword().equals(SecureUtil.md5(password))) {
            return true;
        }
        return false;
    }


    /**
     * 校验支付密码
     * @param userId
     * @param payPassword
     * @return
     */
    public boolean verifyPayPassword(Integer userId, String payPassword) {
        User user = userMapper.selectOneById(userId);
        if (user!=null && user.getPayPassword().equals(SecureUtil.md5(payPassword))) {
            return true;
        }
        return false;
    }

    /**
     * 退出登录
     */
    public void logout(String token, Integer userId) {
        User user = userMapper.selectOneById(userId);
        //清除全局用户
        LoginUser.removeLoginUser();
        //清除redis缓存
        RedisUtils.remove(CommonEnum.LOGIN_KEY.getValue()+token);
        RedisUtils.remove(CommonEnum.LOGIN_KEY.getValue()+user.getUsername());
        log.info("用户{}退出登录",user.getNickName());
    }
}
